
#include "message_logic.h"
#include "amf.h"
#include "rtmp_message.h"
#include <cstddef>
#include <cstdio>
#include <memory>


RtmpMessageProcessLogic::RtmpMessageProcessLogic()
{
    m_stream_id = 0;
}

int RtmpMessageProcessLogic::ProcessRtmpMsg(RtmpPacketMsg & msg, RtmpPacketMsg & response)
{ 
    int result = -1;
    auto & header = msg.m_header;
    switch(header.m_type_id)
    {
        case 0x12:
        {
            std::string command = msg.m_header.m_rtmp_body->GetFirstStr();
            if (command == "@setDataFrame")
            {
            }
        }
        case 0x14:
        {
            std::string command = msg.m_header.m_rtmp_body->GetFirstStr();
            printf("command : %s.\n", command.c_str());
            if (command == "connect")
            {
                ProcessConnect(msg, response);
                result = 0;
            }
            else if (command == "releaseStream")
            {
                ProcessReleaseStream(msg, response);
                result = 0;
            }
            else if (command == "FCPublish")
            {
                printf("process fcpublish data.\n");
                ProcessFCPublish(msg, response);
                result = 0;
            }
            else if (command == "createStream")
            {
                printf("process create stream.\n");
                ProcessCreateStream(msg, response);
                result = 0;
            }
            else if (command == "play")
            {
                printf("process play.\n");
                ProcessPlay(msg, response);
                result = 0;
            }
            else if (command == "publish")
            {
                result = 0;
                ProcessPublish(msg, response);
            }
            break;
        }
        case 0x05:
        {
            break;
        }
    } 
    return result;
}

void RtmpMessageProcessLogic::ProcessConnect(RtmpPacketMsg & msg, RtmpPacketMsg & response)
{
    response.m_header.m_format = 1; 
    response.m_header.m_chunk_stream_id = 3;
    /* response.m_header.m_body_size = msg.m_header.m_body_size; */
    response.m_header.m_type_id = 0x14;
    response.m_header.m_rtmp_body = std::make_shared<RtmpMessageBody>();
    if (response.m_header.m_rtmp_body)
    {
        /* auto & amf_data = response.m_header.m_rtmp_body->GetContent(); */
        auto result = new AmfString();
        result->SetString("_result");
        auto number = new AmfNumber();
        number->SetValue(1);

        response.m_header.m_rtmp_body->AddAmfValue(result);
        response.m_header.m_rtmp_body->AddAmfValue(number);
        // object
        {
            auto object = new AmfObject();
            object->SetString("level", "status");
            object->SetString("code", "NetConnection.Connect.Success");
            object->SetString("description", "Connection succeeded.");
            object->SetNumber("objectEncoding", 0);
            auto sub_object = new AmfObject();
            sub_object->SetString("version", "3,5,1,525");
            object->SetObject("data", sub_object);

            response.m_header.m_rtmp_body->AddAmfValue(object);
        }
        {
            auto object = new AmfObject();
            object->SetString("fmsVer", "FMS/3,5,1,525");
            object->SetNumber("capabilities", 31);
            object->SetNumber("mode", 1);
            response.m_header.m_rtmp_body->AddAmfValue(object);
        }
        printf("body size : %d.\n", response.m_header.m_rtmp_body->BodySize());
    }
    else
    {
        printf("body is empty.\n");
    }
} 

void RtmpMessageProcessLogic::ProcessReleaseStream(RtmpPacketMsg & request, RtmpPacketMsg & response)
{
    response.m_header.m_format = 0x00;
    response.m_header.m_chunk_stream_id = request.m_header.m_chunk_stream_id;
    response.m_header.m_time    = 0;
    response.m_header.m_type_id = request.m_header.m_type_id;
    response.m_header.m_stream_id = request.m_header.m_stream_id;
    response.m_header.m_rtmp_body = std::make_shared<RtmpMessageBody>();
    if (response.m_header.m_rtmp_body)
    {
        auto result = new AmfString();
        result->SetString("_result");
        auto number_id = new AmfNumber();
        number_id->SetValue(request.m_header.m_rtmp_body->GetNumberValue());
        auto nullptr_data = new AmfNull();

        response.m_header.m_rtmp_body->m_content_vec.push_back(result);
        response.m_header.m_rtmp_body->m_content_vec.push_back(number_id);
        response.m_header.m_rtmp_body->m_content_vec.push_back(nullptr_data);
    }
}

void RtmpMessageProcessLogic::ProcessCreateStream(RtmpPacketMsg & request, RtmpPacketMsg & response)
{
    response.m_header.m_format = 0x01;
    response.m_header.m_chunk_stream_id = request.m_header.m_chunk_stream_id;
    response.m_header.m_time = 0;
    response.m_header.m_rtmp_body = std::make_shared<RtmpMessageBody>();
    if (response.m_header.m_rtmp_body)
    {
        response.m_header.m_type_id = 0x14;
        auto result = new AmfString();
        result->SetString("_result");
        auto number = new AmfNumber();
        number->SetValue(request.m_header.m_rtmp_body->GetNumberValue());
        auto null_data = new AmfNull();
        response.m_header.m_rtmp_body->m_content_vec.push_back(result);
        response.m_header.m_rtmp_body->m_content_vec.push_back(number);
        response.m_header.m_rtmp_body->m_content_vec.push_back(null_data);
    }
}

void RtmpMessageProcessLogic::ProcessFCPublish(RtmpPacketMsg & request, RtmpPacketMsg & response)
{
    response.m_header.m_format = 0x00;
    response.m_header.m_chunk_stream_id = request.m_header.m_chunk_stream_id;
    response.m_header.m_time = 0;
    response.m_header.m_body_size = 0;
    response.m_header.m_type_id = request.m_header.m_type_id;
    response.m_header.m_stream_id = request.m_header.m_stream_id;
    response.m_header.m_rtmp_body = std::make_shared<RtmpMessageBody>();
    if (response.m_header.m_rtmp_body)
    {
        auto result = new AmfString();
        result->SetString("_result");
        auto number = new AmfNumber();
        number->SetValue(request.m_header.m_rtmp_body->GetNumberValue());
        auto null_data = new AmfNull();

        response.m_header.m_rtmp_body->m_content_vec.push_back(result);
        response.m_header.m_rtmp_body->m_content_vec.push_back(number);
        response.m_header.m_rtmp_body->m_content_vec.push_back(null_data);

        /* response.m_header.m_body_size = response.m_header.m_body->BodySize(); */
        printf("format : %d chunk stream id : %d.\n", response.m_header.m_format, response.m_header.m_chunk_stream_id);
    }
}

void RtmpMessageProcessLogic::ProcessPlay(RtmpPacketMsg & request, RtmpPacketMsg & response)
{

}

void RtmpMessageProcessLogic::ProcessPublish(RtmpPacketMsg & request, RtmpPacketMsg & response)
{
    std::string stream_name;
    std::string stream_type;
    auto array_data = request.m_header.m_rtmp_body->GetContent();
    for (std::size_t index = 1; index < array_data.size(); index++)
    {
        if (array_data[index]->GetValueType() == STRING && stream_name.empty())
        {
            stream_name = ((AmfString*)array_data[index])->GetValue();
        }
        else if (array_data[index]->GetValueType() == STRING && stream_type.empty())
        {
            stream_type = (((AmfString*)array_data[index]))->GetValue();
        }
    }
    printf("stream name : %s and stream type : %s.\n", stream_name.c_str(), stream_type.c_str());
    response.m_header.m_format = 0x00;
    response.m_header.m_chunk_stream_id = request.m_header.m_chunk_stream_id;
    response.m_header.m_time = request.m_header.m_time;
    response.m_header.m_body_size = 0;
    response.m_header.m_type_id   = request.m_header.m_type_id;
    response.m_header.m_rtmp_body = std::make_shared<RtmpMessageBody>();
    if (response.m_header.m_rtmp_body)
    {
        auto command = new AmfString();
        auto number  = new AmfNumber();
        command->SetString("onFCPublish");
        number->SetValue(0.0);
        auto object_data = new AmfObject();
        {
            object_data->SetString("code", "NetStream.Publish.Start");
            object_data->SetString("description", "Started publishing stream.");
        }
        response.m_header.m_rtmp_body->m_content_vec.push_back(command);
        response.m_header.m_rtmp_body->m_content_vec.push_back(number);
        response.m_header.m_rtmp_body->m_content_vec.push_back(object_data);
        ProcessOnStatus(response);
    }
}

void RtmpMessageProcessLogic::ProcessOnStatus(RtmpPacketMsg & response)
{
    RtmpMessageHeader status_data;
    status_data.m_format = response.m_header.m_format;
    status_data.m_chunk_stream_id = response.m_header.m_chunk_stream_id;
    status_data.m_time = 0;
    status_data.m_type_id = response.m_header.m_type_id;
    status_data.m_rtmp_body = std::make_shared<RtmpMessageBody>();
    
    auto command = new AmfString();
    auto number  = new AmfNumber();
    auto null_data = new AmfNull();
    auto object = new AmfObject();
    
    command->SetString("onStatus");
    number->SetValue(0);
    {
        object->SetString("code", "NetStream.Publish.Start");
        object->SetString("description", "Started publishing stream.");

    }
    status_data.m_rtmp_body->m_content_vec.push_back(command);
    status_data.m_rtmp_body->m_content_vec.push_back(number);
    status_data.m_rtmp_body->m_content_vec.push_back(null_data);
    status_data.m_rtmp_body->m_content_vec.push_back(object);

    response.AddRtmpMsg(status_data);
}

